package com.mooc.server;

import com.mooc.http.HttpRequest;
import com.mooc.http.HttpResponse;
import com.mooc.servlet.Servlet;
import com.mooc.servlet.ServletFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class Server {
    public static Map<String,String> vcode=new HashMap<>();
    // 服务器端口号
    private static final int PORT = 8080;
    // 缓冲区大小
    private static final int BUFFER_SIZE = 8192;
    // 最大连接数
    private static final int MAX_CONNECTIONS = 100;
    // 每秒最大请求数
    private static final int RATE_LIMIT = 10;

    // 定时任务执行器，用于限流
    private static final ScheduledExecutorService rateLimiter = Executors.newScheduledThreadPool(1);
    // 信号量，用于控制每秒请求数量
    private static final Semaphore rateLimitSemaphore = new Semaphore(RATE_LIMIT);
    // 线程池，用于处理读事件
    private static final ExecutorService threadPool = Executors.newFixedThreadPool(10);
    // 原子整数，用于跟踪当前连接数
    private static final AtomicInteger currentConnections = new AtomicInteger(0);
    // 服务器套接字通道
    private static ServerSocketChannel ssc;
    // 选择器
    private static Selector selector;

    public static void run() {
        try {
            // 打开服务器套接字通道
            ssc = ServerSocketChannel.open();
            // 绑定到指定端口
            InetSocketAddress address = new InetSocketAddress(PORT);
            ssc.socket().bind(address);
            // 设置为非阻塞模式
            ssc.configureBlocking(false);

            // 打开选择器
            selector = Selector.open();
            // 将服务器通道注册到选择器上，关注连接事件（OP_ACCEPT）
            ssc.register(selector, SelectionKey.OP_ACCEPT);

            // 定时任务，每秒释放一定数量的许可，重置信号量
            rateLimiter.scheduleAtFixedRate(() ->
                    rateLimitSemaphore.release(RATE_LIMIT - rateLimitSemaphore.availablePermits()), 0, 1, TimeUnit.SECONDS);

            // 事件循环，持续运行服务器
            while (true) {
                // 阻塞等待事件发生


                 int select = selector.select();


                if (select > 0) {
                    // 获取发生的事件集合
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    // 创建事件集合的迭代器
                    Iterator<SelectionKey> it = selectionKeys.iterator();
                    // 遍历所有发生的事件
                    while (it.hasNext()) {
                        // 获取一个事件
                        SelectionKey selectionKey = it.next();
                        try {
                            if (selectionKey.isValid() && selectionKey.isAcceptable()) { // 如果是连接事件
                                handleAccept(selectionKey, selector); // 处理新的客户端连接事件
                            } else if (selectionKey.isValid() && selectionKey.isReadable()) { // 如果是读事件
                                handleRead(selectionKey); // 处理客户端发送的数据事件
                            }
                        } catch (CancelledKeyException e) {
                            closeChannel(selectionKey.channel());
                        } catch (IOException e) {
                            e.printStackTrace(); // 打印异常堆栈跟踪信息
                        }
                        // 移除已处理的事件
                        it.remove();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace(); // 打印异常堆栈跟踪信息
        }
    }

    private static void handleAccept(SelectionKey selectionKey, Selector selector) throws IOException {
        // 获取产生连接事件的通道
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
        if (currentConnections.get() >= MAX_CONNECTIONS) { // 检查当前连接数是否已达到最大连接数
            System.out.println("已达到最大连接数，正在等待连接释放....");
            // 一直循环等待直到有连接被释放
            while (currentConnections.get() >= MAX_CONNECTIONS) {
                try {
                    Thread.sleep(1000); // 每隔1秒检查一次
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        // 接受客户端连接，返回客户端的Socket通道
        SocketChannel socketChannel = serverSocketChannel.accept();
        if (socketChannel != null) { // 如果成功连接客户端
            socketChannel.configureBlocking(false); // 将客户端通道设置为非阻塞模式
            // 将新客户端连接注册到选择器上，关注读事件（OP_READ）
            socketChannel.register(selector, SelectionKey.OP_READ);
            System.out.println("接受来自 " + socketChannel + " 的连接"); // 打印新连接的客户端通道信息
            currentConnections.incrementAndGet(); // 增加当前连接数
        }
    }

    private static void handleRead(SelectionKey selectionKey) {
        threadPool.submit(() -> { // 提交到线程池处理
            boolean acquired = false;
            try {
                acquired = rateLimitSemaphore.tryAcquire();
                if (acquired) { // 尝试获取一个信号量许可，限流控制
                    // 获取产生读事件的通道
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    // 创建一个缓冲区，用于读取数据
                    ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE);
                    // 从通道中读取数据到缓冲区
                    int len = socketChannel.read(byteBuffer);
                    if (len == -1) { // 如果读取到末尾，关闭通道并减少当前连接数
                        closeChannel(socketChannel);
                    } else if (len > 0) { // 如果读取到数据
                        byteBuffer.flip(); // 切换缓冲区到读模式
                        byte[] data = new byte[len]; // 创建字节数组以存储读取的数据
                        byteBuffer.get(data); // 将数据从缓冲区中取出
                        String msg = new String(data, 0, len); // 将字节数组转换为字符串
                        System.out.println(msg); // 打印请求信息
                        HttpRequest httpRequest = new HttpRequest(msg); // 解析HTTP请求
                        HttpResponse httpResponse = new HttpResponse(socketChannel); // 创建HTTP响应
                        // 根据请求URL获取相应的Servlet
                        Servlet servlet = ServletFactory.getServlet(httpRequest.getRequestUrl());
                        servlet.service(httpRequest, httpResponse); // 调用Servlet处理请求
                    }
                } else {
                    System.out.println("超过速率限制，请求删除...."); // 如果超过限流，丢弃请求
                }
            } catch (ClosedChannelException e) {
                closeChannel(selectionKey.channel());
            } catch (IOException e) {
                e.printStackTrace(); // 打印异常堆栈跟踪信息
            } finally {
                if (acquired) {
                    rateLimitSemaphore.release();
                }
            }
        });
    }

    private static void closeChannel(Channel channel) {
        try {
            if (channel != null && channel.isOpen()) {
                channel.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 关闭服务器
    public static void shutdown() {
        try {
            if (selector != null) {
                selector.close();
            }
            if (ssc != null) {
                ssc.close();
            }
            rateLimiter.shutdown();
            threadPool.shutdown();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
